home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1997 April
/
EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso
/
SoftwareUpdate
/
CyberGraphiX Update
/
CV64VBlankHack.lha
/
CV64VBlankHack
/
CV64VBlankHack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-28
|
7KB
|
275 lines
/* Installs a new VBLANK handler that kicks in when a CyberGraphX screen
is being displayed.
VBeamPos() is also patched to return the correct scan line.
This is a HACK. It's Quick and it's Dirty. I don't care if it doesn't work
for you, it does for me.
Done by Martin 'Leviticus' Blom in 1996 (lcs@lysator.liu.se).
Public Domain. Feel free to improve it, and perhaps write a more lowlevel version.
Just keep my name in it if you base anything on this.
*/
/*
** Graphic card settings
*/
#define MANUFACTURER 8512 // Phase 5
#define PRODUCT 34 // CyberVision 64
#define VGAOFFSET 0x02000000 // Where are the VGA registers located?
/*
** MARGIN is... well see the line where the period is set. It should be less than
** 1.0, but as close as possible without missing vblanks.
** If you set it to 5/10, for example, you'll loose 50% of your CPU power!
** 9/10 works fine on my A4000. If I didn't use timer.device, but used a
** level 6 timer directly instead, this number could probably be raised. But since
** I hate programs that uses CIA timers, I didn't.
*/
#define MARGIN 90/100
#include <exec/exec.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <graphics/gfxbase.h>
#include <hardware/intbits.h>
#include <hardware/cia.h>
#include <cybergraphics/cybergraphics.h>
#include <libraries/configvars.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/timer.h>
#include <proto/cybergraphics.h>
#include <proto/expansion.h>
extern struct ExecBase *SysBase;
extern __far struct CIA ciaa;
extern void NewVBLANKHandler(void);
extern void __asm CallVBLANKServers(register __a6 struct ExecBase *);
extern LONG __asm WaitVBLANK( register __a0 UBYTE * );
extern LONG __asm myReadEClock(void);
void start(void);
void softcode (void);
LONG __saveds newVBeamPos(void);
struct Library *TimerBase=NULL;
#define OFF 0 // Shut down
#define ON 1 // Run
#define STOPPED 2 // Has shut down
struct Data
{
UWORD d_Flag;
struct MsgPort *d_Port;
};
struct Data *data;
struct NewVBLANKData
{
ULONG nd_OldEnable; // Enables old VBLANK code
VOID (*nd_Code)(); // Old iv_Code
};
struct NewVBLANKData *NewVBLANKdata;
struct MonitorInfo mi;
#define DEFPERIOD 1000 //00
ULONG period=DEFPERIOD;
LONG (*oldVBeamPos)();
UBYTE *vgaregs=NULL;
/*
** I dont know if it's just me, but isn't timer.device's ReadEClock() broken?
** Anyway, I use my own routine.
*/
LONG Eclock; // E-clock value last VBLANK
LONG Efreq;
struct EClockVal eclockpad; // Unused
long main(void)
{
struct ConfigDev *cd;
cd=FindConfigDev( NULL, MANUFACTURER, PRODUCT );
if(!cd)
return 20;
// Graphics card found:
vgaregs=(UBYTE *) cd->cd_BoardAddr+VGAOFFSET;
if(NewVBLANKdata = AllocVec(sizeof(struct NewVBLANKData), MEMF_PUBLIC|MEMF_CLEAR))
{
NewVBLANKdata->nd_OldEnable=TRUE;
/*
** Change the vblank *HANDLER*.
*/
// Store old code segment and install our own (leave data segment untouched)
Disable();
NewVBLANKdata->nd_Code=SysBase->IntVects[INTB_VERTB].iv_Code;
SysBase->IntVects[INTB_VERTB].iv_Code=NewVBLANKHandler;
Enable();
// Install new VBeamPos code
oldVBeamPos=SetFunction((struct Library *)GfxBase, -384, (ULONG (* )()) newVBeamPos);
start();
// Install old VBeamPos code
SetFunction((struct Library *)GfxBase, -384, (ULONG (* )()) oldVBeamPos);
// Restore old code segment
SysBase->IntVects[INTB_VERTB].iv_Code=NewVBLANKdata->nd_Code;
FreeVec(NewVBLANKdata);
}
return NULL;
}
void start(void)
{
struct MsgPort *port;
struct Interrupt *softint;
struct timerequest *timereq;
ULONG id;
BOOL done=FALSE;
if(data = AllocVec(sizeof(struct Data), MEMF_PUBLIC|MEMF_CLEAR))
{
if(port = AllocVec(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR))
{
NewList(&(port->mp_MsgList));
if(softint = AllocVec(sizeof(struct Interrupt), MEMF_PUBLIC|MEMF_CLEAR))
{
softint->is_Code=softcode;
softint->is_Data=data;
softint->is_Node.ln_Pri=32;
port->mp_Node.ln_Type = NT_MSGPORT;
port->mp_Flags= PA_SOFTINT;
port->mp_SigTask = (struct Task *) softint;
if(timereq= (struct timerequest *) CreateIORequest(port, sizeof(struct timerequest)))
{
if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) timereq, 0))
{
TimerBase=(struct Library *) timereq->tr_node.io_Device;
Efreq=ReadEClock(&eclockpad); // Just get the E clock frequency
Printf("%ld\n",Efreq);
data->d_Flag=ON;
data->d_Port=port;
timereq->tr_node.io_Command=TR_ADDREQUEST;
timereq->tr_time.tv_micro=DEFPERIOD;
BeginIO((struct IORequest *) timereq);
while(!done)
{
// Keep checking the frontmost intuition screen
id=GetVPModeID(&IntuitionBase->FirstScreen->ViewPort);
if(IsCyberModeID(id))
{
// CyberGraphX screen
if(GetDisplayInfoData(NULL,(UBYTE *) &mi, sizeof mi, DTAG_MNTR,id))
{
period=mi.TotalRows*mi.TotalColorClocks*280*MARGIN/1000; // in µs
NewVBLANKdata->nd_OldEnable=FALSE;
}
else
{
NewVBLANKdata->nd_OldEnable=TRUE;
period=DEFPERIOD;
}
}
else
{
// Native screen
NewVBLANKdata->nd_OldEnable=TRUE;
period=DEFPERIOD;
}
Delay(10);
if(SetSignal(0L,SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
{
done=TRUE;
}
}
Printf("%ld\n",newVBeamPos());
NewVBLANKdata->nd_OldEnable=TRUE;
period=DEFPERIOD;
data->d_Flag=OFF;
while(data->d_Flag != STOPPED) Delay(10);
CloseDevice((struct IORequest *) timereq);
}
DeleteIORequest((struct IORequest *) timereq);
}
FreeVec(softint);
}
FreeVec(port);
}
FreeVec(data);
}
}
void __saveds __interrupt softcode(void)
{
struct timerequest *timereq;
timereq=(struct timerequest *) GetMsg(data->d_Port);
if( (timereq) && (data->d_Flag == ON) )
{
if(!(NewVBLANKdata->nd_OldEnable))
{
Eclock=WaitVBLANK(vgaregs);
CallVBLANKServers(SysBase);
}
timereq->tr_node.io_Command=TR_ADDREQUEST;
// Period in µs. The main task keeps updating this value all the time.
timereq->tr_time.tv_micro=period;
BeginIO((struct IORequest *) timereq);
}
else
data->d_Flag=STOPPED;
}
LONG __saveds newVBeamPos(void)
{
LONG ediff;
if(NewVBLANKdata->nd_OldEnable)
return (*oldVBeamPos)();
ediff=Eclock-myReadEClock();
if(ediff<0)
ediff+=65536;
// Return (approx) current raster line. mi.TotalRows disappears...
// HOWEVER: The range is NOT limited to 511 anymore. I don't know if this is a problem?
return ediff*(1000000000/280/mi.TotalColorClocks)/Efreq;
}